use crate::ast::*;
use crate::error::{CompilerError, Result};
use inkwell::types::BasicTypeEnum;
use inkwell::values::BasicValueEnum;

use super::super::LLVMBackend;

impl<'ctx> LLVMBackend<'ctx> {
    pub(in crate::llvm_backend) fn infer_expression_type(&self, expr: &Expression) -> Option<Type> {
        match expr {
            Expression::Variable(name) => {
                // Look up variable type
                self.variable_type_map.get(name).cloned()
            }
            Expression::Unary(unary) => {
                // For dereference, get the pointee type
                if matches!(unary.operator, UnaryOp::Deref) {
                    if let Expression::Variable(var_name) = &*unary.operand {
                        if let Some(var_type) = self.variable_type_map.get(var_name) {
                            match var_type {
                                Type::Reference(ref_type) => {
                                    return Some(*ref_type.referenced_type.clone());
                                }
                                _ => {}
                            }
                        }
                    }
                }
                // For other unary ops, infer from operand
                self.infer_expression_type(&unary.operand)
            }
            Expression::Binary(binary) => {
                // For binary operations, infer from left operand
                // (both operands should have same type after type checking)
                self.infer_expression_type(&binary.left)
            }
            Expression::Call(call) => {
                // Handle function literal/closure as callee
                if let Expression::FunctionLiteral(func_lit) = &*call.callee {
                    // First, try to get return type from function_type
                    if let Some(Type::Function(func_type)) = &func_lit.function_type {
                        if let Some(return_type) = &func_type.return_type {
                            return Some(*return_type.clone());
                        }
                    }
                    // If function_type doesn't have return type, try to get it from lambda
                    if let Some(lambda) = &func_lit.lambda {
                        if let Some(return_type) = &lambda.return_type {
                            return Some(return_type.clone());
                        }
                    }
                }

                // Handle variable that holds a function pointer
                if let Expression::Variable(var_name) = &*call.callee {
                    if let Some(Type::Function(func_type)) = self.variable_type_map.get(var_name) {
                        // Return the function's return type directly
                        return func_type.return_type.as_ref().map(|t| *t.clone());
                    }
                }

                // Extract function name from callee
                if let Expression::Variable(func_name) = &*call.callee {
                    if let Some(func_decl) = self.function_decls.get(func_name) {
                        if let Some(return_type) = &func_decl.return_type {
                            return Some(return_type.clone());
                        }
                    }
                    // Look up function return type
                    if let Some(func_value) = self.function_map.get(func_name) {
                        // Get function signature
                        let func_type = func_value.get_type();
                        let return_type = func_type.get_return_type()?;

                        // Convert LLVM type back to NRC type
                        use inkwell::types::BasicTypeEnum;
                        match return_type {
                            BasicTypeEnum::IntType(int_type) => match int_type.get_bit_width() {
                                1 => Some(Type::Basic(types::BasicType::Bool)),
                                8 => Some(Type::Basic(types::BasicType::Int8)),
                                16 => Some(Type::Basic(types::BasicType::Int16)),
                                32 => Some(Type::Basic(types::BasicType::Int32)),
                                64 => Some(Type::Basic(types::BasicType::Int64)),
                                _ => None,
                            },
                            BasicTypeEnum::FloatType(_) => {
                                Some(Type::Basic(types::BasicType::Float32))
                            }
                            BasicTypeEnum::PointerType(_) => {
                                // Could be string or other pointer type
                                Some(Type::Basic(types::BasicType::String))
                            }
                            BasicTypeEnum::StructType(_) => {
                                // For struct types, try to infer from function name or context
                                // This is a fallback - ideally we'd have type information stored
                                None
                            }
                            _ => None,
                        }
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            Expression::MethodCall(method_call) => {
                // First, try heuristic inference for well-known methods
                // This ensures we can infer type even when method is not in function_map
                match method_call.method.as_str() {
                    "to_string" | "toString" => {
                        // to_string always returns String
                        return Some(Type::Basic(types::BasicType::String));
                    }
                    "draw" | "render" => {
                        // draw/render methods return void
                        return Some(Type::Basic(types::BasicType::Void));
                    }
                    _ => {}
                }

                // Try to infer receiver type
                let receiver_type_opt = self.infer_expression_type(&method_call.object);
                let receiver_type_cloned = receiver_type_opt.clone();

                if let Some(receiver_type) = receiver_type_opt.clone() {
                    match receiver_type {
                        Type::Option(option_type) => match method_call.method.as_str() {
                            "is_some" | "is_none" => {
                                return Some(Type::Basic(types::BasicType::Bool));
                            }
                            "unwrap" => {
                                return Some(*option_type.some_type.clone());
                            }
                            _ => {}
                        },
                        Type::Result(result_type) => match method_call.method.as_str() {
                            "is_ok" | "is_err" => {
                                return Some(Type::Basic(types::BasicType::Bool));
                            }
                            "unwrap" => {
                                return Some(*result_type.ok_type.clone());
                            }
                            "unwrap_err" => {
                                return Some(*result_type.err_type.clone());
                            }
                            _ => {}
                        },
                        _ => {}
                    }
                }

                // Try to find method by checking all struct types
                // This handles cases where we don't have full type information yet
                for struct_name in self.struct_declarations.keys() {
                    let method_name_with_type = format!("{}.{}", struct_name, method_call.method);
                    if self.function_map.contains_key(&method_name_with_type) {
                        if let Some(func_value) = self.function_map.get(&method_name_with_type) {
                            let func_type = func_value.get_type();
                            if let Some(return_type) = func_type.get_return_type() {
                                // Convert LLVM type back to NRC type
                                match return_type {
                                    BasicTypeEnum::IntType(int_type) => {
                                        match int_type.get_bit_width() {
                                            1 => return Some(Type::Basic(types::BasicType::Bool)),
                                            8 => return Some(Type::Basic(types::BasicType::Int8)),
                                            16 => {
                                                return Some(Type::Basic(types::BasicType::Int16))
                                            }
                                            32 => {
                                                return Some(Type::Basic(types::BasicType::Int32))
                                            }
                                            64 => {
                                                return Some(Type::Basic(types::BasicType::Int64))
                                            }
                                            _ => {
                                                // Unknown int type, continue to next check
                                                continue;
                                            }
                                        }
                                    }
                                    BasicTypeEnum::FloatType(_) => {
                                        return Some(Type::Basic(types::BasicType::Float32));
                                    }
                                    BasicTypeEnum::PointerType(_) => {
                                        // For string return types (like to_string), return String type
                                        if method_call.method == "to_string"
                                            || method_call.method.contains("string")
                                        {
                                            return Some(Type::Basic(types::BasicType::String));
                                        }
                                        return Some(Type::Basic(types::BasicType::String));
                                    }
                                    BasicTypeEnum::StructType(_) => {
                                        // For struct return types, try to infer from struct name
                                        // Try to get struct type from receiver if available
                                        if let Some(Type::Struct(receiver_struct_type)) =
                                            &receiver_type_opt
                                        {
                                            if method_call.method == "get_position"
                                                || method_call.method.contains("get_")
                                            {
                                                return Some(Type::Struct(
                                                    receiver_struct_type.clone(),
                                                ));
                                            }
                                        }
                                        // If receiver type not available, infer from struct name in method name
                                        return Some(Type::Struct(StructType {
                                            name: struct_name.clone(),
                                            type_args: vec![],
                                            location: method_call.location,
                                        }));
                                    }
                                    _ => {
                                        // Unknown return type, continue to next struct check
                                        continue;
                                    }
                                }
                            } else {
                                // Void return type
                                return Some(Type::Basic(types::BasicType::Void));
                            }
                        }
                    }
                }

                // If we got here, method was not found in function_map
                // Try heuristic inference based on method name before checking receiver type
                // This ensures we can infer type even when receiver type is unknown
                if let Some(heuristic_type) = match method_call.method.as_str() {
                    "to_string" | "toString" => Some(Type::Basic(types::BasicType::String)),
                    "draw" | "render" => Some(Type::Basic(types::BasicType::Void)),
                    _ => None,
                } {
                    return Some(heuristic_type);
                }

                // If receiver type is known, try to use it
                if let Some(receiver_type) = &receiver_type_opt {
                    if let Type::Struct(struct_type) = receiver_type {
                        let method_name = format!("{}.{}", struct_type.name, method_call.method);
                        if let Some(func_value) = self.function_map.get(&method_name) {
                            let func_type = func_value.get_type();
                            if let Some(return_type) = func_type.get_return_type() {
                                // Convert LLVM type back to NRC type
                                match return_type {
                                    BasicTypeEnum::IntType(int_type) => {
                                        match int_type.get_bit_width() {
                                            1 => return Some(Type::Basic(types::BasicType::Bool)),
                                            8 => return Some(Type::Basic(types::BasicType::Int8)),
                                            16 => {
                                                return Some(Type::Basic(types::BasicType::Int16))
                                            }
                                            32 => {
                                                return Some(Type::Basic(types::BasicType::Int32))
                                            }
                                            64 => {
                                                return Some(Type::Basic(types::BasicType::Int64))
                                            }
                                            _ => return None,
                                        }
                                    }
                                    BasicTypeEnum::FloatType(_) => {
                                        return Some(Type::Basic(types::BasicType::Float32));
                                    }
                                    BasicTypeEnum::PointerType(_) => {
                                        // For string return types
                                        return Some(Type::Basic(types::BasicType::String));
                                    }
                                    BasicTypeEnum::StructType(_) => {
                                        // For struct return types
                                        if method_call.method == "get_position"
                                            || method_call.method.contains("get_")
                                        {
                                            return Some(receiver_type.clone());
                                        }
                                        return Some(Type::Struct(struct_type.clone()));
                                    }
                                    _ => return None,
                                }
                            } else {
                                return Some(Type::Basic(types::BasicType::Void));
                            }
                        }
                    }
                }

                // If not found, try regular function name
                if let Some(func_value) = self.function_map.get(&method_call.method) {
                    let func_type = func_value.get_type();
                    if let Some(return_type) = func_type.get_return_type() {
                        match return_type {
                            BasicTypeEnum::IntType(int_type) => match int_type.get_bit_width() {
                                1 => Some(Type::Basic(types::BasicType::Bool)),
                                8 => Some(Type::Basic(types::BasicType::Int8)),
                                16 => Some(Type::Basic(types::BasicType::Int16)),
                                32 => Some(Type::Basic(types::BasicType::Int32)),
                                64 => Some(Type::Basic(types::BasicType::Int64)),
                                _ => None,
                            },
                            BasicTypeEnum::FloatType(_) => {
                                Some(Type::Basic(types::BasicType::Float32))
                            }
                            BasicTypeEnum::PointerType(_) => {
                                Some(Type::Basic(types::BasicType::String))
                            }
                            _ => None,
                        }
                    } else {
                        Some(Type::Basic(types::BasicType::Void))
                    }
                } else {
                    // If method not found in function_map, try heuristic inference based on method name
                    // This handles cases where the method hasn't been registered yet
                    // Note: This should already be handled above (line 142-148), but keep as fallback
                    match method_call.method.as_str() {
                        "to_string" | "toString" => {
                            // to_string always returns String
                            Some(Type::Basic(types::BasicType::String))
                        }
                        "get_position" | "position" => {
                            // Try to return receiver type if known
                            receiver_type_cloned.or_else(|| {
                                // If receiver type unknown, return a generic Point struct
                                // This is a fallback for get_position
                                Some(Type::Struct(StructType {
                                    name: "Point".to_string(),
                                    type_args: vec![],
                                    location: method_call.location,
                                }))
                            })
                        }
                        "draw" | "render" => Some(Type::Basic(types::BasicType::Void)),
                        _ => {
                            // For unknown methods, if receiver type is known, try to infer from method name pattern
                            if let Some(Type::Struct(struct_type)) = &receiver_type_opt {
                                // For "get_*" methods, assume they return the receiver type
                                if method_call.method.starts_with("get_") {
                                    Some(Type::Struct(struct_type.clone()))
                                } else {
                                    // For other methods with unknown return type, try to infer from receiver
                                    // For methods like "to_string", "get_position", etc., use heuristic
                                    None
                                }
                            } else {
                                // If receiver type is unknown, but method is known by name, use heuristic
                                // This is a fallback when we can't infer receiver type
                                // Try heuristic one more time as absolute fallback
                                None
                            }
                        }
                    }
                }
            }
            Expression::Literal(lit) => {
                match lit {
                    // Default to 'int' (i64) for integer literals, matching Go/Rust behavior
                    Literal::Integer(_) => Some(Type::Basic(types::BasicType::Int)),
                    Literal::Float(_) => Some(Type::Basic(types::BasicType::Float64)),
                    Literal::String(_) => Some(Type::Basic(types::BasicType::String)),
                    Literal::Boolean(_) => Some(Type::Basic(types::BasicType::Bool)),
                    _ => None,
                }
            }
            Expression::Struct(struct_expr) => {
                // Return the struct type from the expression
                Some(struct_expr.struct_type.clone())
            }
            _ => None,
        }
    }

    /// Generate unary expression

    /// Convert NRC type to LLVM type
    /// Cast a value to the target type if needed
    pub(in crate::llvm_backend) fn cast_value_to_type(
        &self,
        value: BasicValueEnum<'ctx>,
        target_type: BasicTypeEnum<'ctx>,
    ) -> Result<BasicValueEnum<'ctx>> {
        // Check if it's the exact same type and cast if needed
        match (value, target_type) {
            (BasicValueEnum::IntValue(int_val), BasicTypeEnum::IntType(target_int_type)) => {
                let source_width = int_val.get_type().get_bit_width();
                let target_width = target_int_type.get_bit_width();

                if source_width == target_width {
                    Ok(int_val.into())
                } else if source_width < target_width {
                    // Sign extend
                    Ok(self
                        .builder
                        .build_int_s_extend(int_val, target_int_type, "cast")?
                        .into())
                } else {
                    // Truncate
                    Ok(self
                        .builder
                        .build_int_truncate(int_val, target_int_type, "cast")?
                        .into())
                }
            }
            (
                BasicValueEnum::FloatValue(float_val),
                BasicTypeEnum::FloatType(target_float_type),
            ) => {
                let source_type = float_val.get_type();
                if source_type == target_float_type {
                    Ok(float_val.into())
                } else {
                    // Float cast (f64 -> f32 or f32 -> f64)
                    Ok(self
                        .builder
                        .build_float_cast(float_val, target_float_type, "cast")?
                        .into())
                }
            }
            (BasicValueEnum::IntValue(int_val), BasicTypeEnum::FloatType(float_type)) => {
                // int -> float
                Ok(self
                    .builder
                    .build_signed_int_to_float(int_val, float_type, "cast")?
                    .into())
            }
            (BasicValueEnum::FloatValue(float_val), BasicTypeEnum::IntType(int_type)) => {
                // float -> int
                Ok(self
                    .builder
                    .build_float_to_signed_int(float_val, int_type, "cast")?
                    .into())
            }
            (v, _) => {
                // Same type or no conversion needed
                Ok(v)
            }
        }
    }

    pub(in crate::llvm_backend) fn is_string_literal(&self, expr: &Expression) -> bool {
        matches!(
            expr,
            Expression::Literal(crate::ast::expr::Literal::String(_))
        )
    }

    pub(in crate::llvm_backend) fn is_string_field_access(&self, expr: &Expression) -> bool {
        match expr {
            Expression::FieldAccess(field_access) => {
                // Check if this is accessing a string field by looking up the struct declaration
                if let Some(struct_decl) =
                    self.resolve_struct_for_field_access(&field_access.object, &field_access.field)
                {
                    // Find the field and check if it's a string type
                    if let Some(field) = struct_decl
                        .fields
                        .iter()
                        .find(|field| field.name == field_access.field)
                    {
                        matches!(
                            field.field_type,
                            crate::ast::types::Type::Basic(crate::ast::types::BasicType::String)
                        )
                    } else {
                        false
                    }
                } else {
                    // Fallback to hardcoded check for known string fields
                    field_access.field == "name" || field_access.field == "address"
                }
            }
            Expression::Variable(var_name) => {
                // Check if this is a string parameter (like "name" parameter)
                // This is a heuristic - we assume variables named "name" are strings
                var_name == "name" || var_name.ends_with("_name") || var_name.starts_with("name_")
            }
            _ => false,
        }
    }

    /// Execute all deferred statements in LIFO order

    /// 处理赋值表达式
    #[allow(dead_code)]
    pub(super) fn handle_assignment_expression(
        &mut self,
        _left: BasicValueEnum<'ctx>,
        _right: BasicValueEnum<'ctx>,
    ) -> Result<()> {
        // 手动内存管理：直接赋值，不需要引用计数管理
        Ok(())
    }

    /// Helper function to find struct declaration by field name

    /// Get struct pointer from a variable (helper for field access and assignment)
    /// Handles both pointer variables and struct value variables

    /// Generate zero value for a given type (Go-style zero values)
    pub(in crate::llvm_backend) fn generate_zero_value(
        &mut self,
        nrc_type: &Type,
    ) -> Result<BasicValueEnum<'ctx>> {
        use crate::ast::types::BasicType as NRCBasicType;
        use inkwell::AddressSpace;

        match nrc_type {
            Type::Basic(basic_type) => {
                match basic_type {
                    // Integer types: zero
                    NRCBasicType::Int | NRCBasicType::Int64 => {
                        Ok(self.context.i64_type().const_int(0, false).into())
                    }
                    NRCBasicType::Int8 => Ok(self.context.i8_type().const_int(0, false).into()),
                    NRCBasicType::Int16 => Ok(self.context.i16_type().const_int(0, false).into()),
                    NRCBasicType::Int32 => Ok(self.context.i32_type().const_int(0, false).into()),
                    // Unsigned integer types: zero
                    NRCBasicType::Uint | NRCBasicType::Uint64 => {
                        Ok(self.context.i64_type().const_int(0, false).into())
                    }
                    NRCBasicType::Uint8 => Ok(self.context.i8_type().const_int(0, false).into()),
                    NRCBasicType::Uint16 => Ok(self.context.i16_type().const_int(0, false).into()),
                    NRCBasicType::Uint32 => Ok(self.context.i32_type().const_int(0, false).into()),
                    // Float types: 0.0
                    NRCBasicType::Float32 => Ok(self.context.f32_type().const_float(0.0).into()),
                    NRCBasicType::Float64 => Ok(self.context.f64_type().const_float(0.0).into()),
                    // Bool: false
                    NRCBasicType::Bool => Ok(self.context.bool_type().const_int(0, false).into()),
                    // String: null pointer
                    NRCBasicType::String => Ok(self
                        .context
                        .i8_type()
                        .ptr_type(AddressSpace::default())
                        .const_null()
                        .into()),
                    // Char: '\0'
                    NRCBasicType::Char => Ok(self.context.i8_type().const_int(0, false).into()),
                    // Rune: 0 (Unicode code point U+0000)
                    NRCBasicType::Rune => Ok(self.context.i32_type().const_int(0, false).into()),
                    _ => Err(CompilerError::internal(&format!(
                        "Unsupported basic type for zero value: {:?}",
                        basic_type
                    ))),
                }
            }
            // Reference counted types: nil (null pointer) or zeroed trait handle
            Type::Rc(rc_type) => {
                if let Some(trait_name) = self.trait_name_from_type(&rc_type.inner_type) {
                    let handle_type = self.ensure_trait_rc_handle_type(&trait_name);
                    Ok(handle_type.const_zero().into())
                } else {
                    Ok(self
                        .context
                        .i8_type()
                        .ptr_type(AddressSpace::default())
                        .const_null()
                        .into())
                }
            }
            Type::Weak(weak_type) => {
                if let Some(trait_name) = self.trait_name_from_type(&weak_type.inner_type) {
                    let handle_type = self.ensure_trait_weak_handle_type(&trait_name);
                    Ok(handle_type.const_zero().into())
                } else {
                    Ok(self
                        .context
                        .i8_type()
                        .ptr_type(AddressSpace::default())
                        .const_null()
                        .into())
                }
            }
            _ => Err(CompilerError::internal(&format!(
                "Unsupported type for zero value: {:?}",
                nrc_type
            ))),
        }
    }
}
